package weixin

import (
	"bytes"
	"encoding/json"
	"fmt"
	"gogo/log"
	"net/http"
	"net/url"
	"time"
)

var (
	mp_weixin *Weixin_Class
)

func This() *Weixin_Class {
	if mp_weixin == nil {
		mp_weixin = &Weixin_Class{}
	}
	return mp_weixin
}

type Weixin_Class struct {
	tx_ip_map map[string]int //腾讯服务器IP

	Corpid       string //企业ID
	AgentId      string //应用ID
	Secret       string //Secret
	mAccessToken string //企业微信AccessToken
}

func (c *Weixin_Class) Init(Corpid, AgentId, Secret string) {
	c.Corpid = Corpid
	c.AgentId = AgentId
	c.Secret = Secret
}

func (c *Weixin_Class) SendToBarkf(title, format string, args ...interface{}) {
	c.SendToBark(title, fmt.Sprintf(format, args...))
}

func (c *Weixin_Class) SendToBark(title, content string) {
	new_content := fmt.Sprintf("时间: %s\n%s", time.Now().Format("2006-01-02 15:04:05"), content)
	c.httpGetJson(fmt.Sprintf("https://msg.kony.cool/kony/%s/%s?isArchive=1", title, url.QueryEscape(new_content)))
}

func (c *Weixin_Class) Sendf(toUser, toParty, title, format string, args ...interface{}) {
	c.Send(toUser, toParty, title, fmt.Sprintf(format, args...))
}

func (c *Weixin_Class) Send(toUser, toParty, title, content string) {
	new_content := fmt.Sprintf("时间: %s\n", time.Now().Format("2006-01-02 15:04:05"))
	new_content += content
	go c.sendCardMsg(toUser, toParty, title, new_content, 1)
	//SendToBarkf("%s\n---------\n该消息推送给了%s", content, getPartyName(toParty))
}

func (c *Weixin_Class) getAccessToken(force bool) string {
	var accessToken string

	/*if !force {
		accessToken = redis_client.Get(redis_client.OtherDBName, redis_client.CommonDBName_QiYeWeiXinAccessToken)
		if accessToken != "" {
			return accessToken
		}
	}*/

	qyurl := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s", c.Corpid, c.Secret)
	data, err := c.httpGetJson(qyurl)
	if err != nil {
		log.This().ErrorF("getAccessToken error:", err)
		return ""
	}
	errcode := data["errcode"].(float64)
	if errcode != 0 {
		log.This().ErrorF("getAccessToken error:", data["errmsg"].(string))
		return ""
	}

	accessToken = data["access_token"].(string)
	//redis_client.SetNx(redis_client.OtherDBName, redis_client.CommonDBName_QiYeWeiXinAccessToken, accessToken, 4800*time.Second)
	return accessToken
}

// 企业微信应用消息提醒方法如下
func (c *Weixin_Class) sendCardMsg(toUser, toParty interface{}, title, description string, level int) (map[string]interface{}, error) {
	switch level {
	case 1:
		if c.mAccessToken == "" {
			return c.sendCardMsg(toUser, toParty, title, description, 2)
		}
	case 2:
		c.mAccessToken = c.getAccessToken(false)
	case 3:
		c.mAccessToken = c.getAccessToken(true)
	default:
		return nil, fmt.Errorf("level error")
	}

	btntxt := "详情" //可自定义卡片底下的文字

	//卡片内容，不同类型消息通知以下内容需修改(可参考企业微信开发文档)
	req := map[string]interface{}{
		"msgtype": "textcard",
		"agentid": c.AgentId,
		"textcard": map[string]interface{}{
			"title":       title,
			"description": description,
			"url":         "https://www.baidu.com",
			"btntext":     btntxt,
		},
	}

	if toUser != "" {
		req["touser"] = toUser
	} else if toParty != "" {
		req["toparty"] = toParty
	}

	sendurl := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s", c.mAccessToken)
	data, err := c.httpPostJson(sendurl, req)
	if err != nil {
		log.This().ErrorF("sendCardMsg %s", err)
		return nil, err
	}
	if value, ok := data["errcode"]; ok && value != nil {
		if value.(float64) == 40014 {
			return c.sendCardMsg(toUser, toParty, title, description, level+1)
		}
	}
	return data, nil
}

// 封装了http请求的GET和POST方法，其返回值都是map[string]interface{}，方便我们使用。
func (c *Weixin_Class) httpGetJson(url string) (map[string]interface{}, error) {
	res, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	var data map[string]interface{}
	err = json.NewDecoder(res.Body).Decode(&data)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func (c *Weixin_Class) httpPostJson(url string, data map[string]interface{}) (map[string]interface{}, error) {
	res, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	resp, err := http.Post(url, "application/json", bytes.NewReader(res))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var data2 map[string]interface{}
	err = json.NewDecoder(resp.Body).Decode(&data2)
	if err != nil {
		return nil, err
	}
	return data2, nil
}
